﻿using System;
using System.Collections.Generic;
using System.Data.Entity;
using System.Linq;
using AutoMapper;
using AutoMapper.QueryableExtensions;
using Mehdime.Entity;
using WikeSoft.Core;
using WikeSoft.Core.Exception;
using WikeSoft.Core.Extension;
using WikeSoft.Data;
using WikeSoft.Data.Models;
using WikeSoft.Data.Models.Sys;
using WikeSoft.Enterprise.Entities;
using WikeSoft.Enterprise.Interfaces.Sys;
using WikeSoft.Enterprise.Models;
using WikeSoft.Enterprise.Models.Filters.Sys;
using WikeSoft.Enterprise.Models.Sys;

namespace WikeSoft.Enterprise.AppServices.Sys
{
    /// <summary>
    /// 页面服务
    /// </summary>
    public class PageService : IPageService
    {
        private readonly IMapper _mapper;
        private readonly IDbContextScopeFactory _dbContextScopeFactory;
        private readonly IConfigurationProvider _configurationProvider;

        public PageService(IMapper mapper, 
            IDbContextScopeFactory dbContextScopeFactory,
            IConfigurationProvider configurationProvider)
        {
            _mapper = mapper;
            _dbContextScopeFactory = dbContextScopeFactory;
            _configurationProvider = configurationProvider;
        }

        /// <summary>
        ///  添加
        /// </summary>
        /// <param name="model"></param>
        /// <returns></returns>
        public bool Add(PageAddModel model)
        {
            using (var scope = _dbContextScopeFactory.Create())
            {
                var db = scope.DbContexts.Get<WikeDbContext>();
                var entity = _mapper.Map<PageAddModel, SysPage>(model);
                //处理页面与角色间的关系
                //if (model.RoleIds.AnyOne())
                //{
                //    entity.SysRoles = db.SysRoles.Where(x => model.RoleIds.Contains(x.Id)).ToList();
                //}
                //设置页面的路劲码
                entity.PathCode = GetPathCode(db, model.ParentId);
                db.SysPages.Add(entity);
                return scope.SaveChanges() > 0;
            }
        }

        /// <summary>
        ///  编辑
        /// </summary>
        /// <param name="model"></param>
        /// <returns></returns>
        public bool Edit(PageEditModel model)
        {
            using (var scope = _dbContextScopeFactory.Create())
            {
                var db = scope.DbContexts.Get<WikeDbContext>();
                var entity = db.SysPages.Load(model.Id);

                var subs = db.SysDepartments.Where(c => c.PathCode.StartsWith(entity.PathCode) && c.Id != model.Id).ToList();
                var subIds = subs.Select(c => c.Id).ToList();
                if (model.ParentId != null && subIds.Contains(model.ParentId))
                {
                    throw new TipInfoException("上级节点不能为当前节点的下级节点");
                }
                if (model.Id == model.ParentId)
                {
                    throw new TipInfoException("上级节点不能为当前节点");
                }
                var oldId = entity.ParentId;
                var newId = model.ParentId;
                var oldPathCode = entity.PathCode;
                _mapper.Map(model, entity);
                if (!oldId.Equals(newId))
                {
                    var pathCode = GetPathCode(db, newId);

                    subs.ForEach(c =>
                    {
                        c.PathCode = c.PathCode.Replace(oldPathCode, pathCode);
                    });

                    entity.PathCode = pathCode;
                }
                return scope.SaveChanges() > 0;
            }
        }

        /// <summary>
        ///  删除
        /// </summary>
        /// <param name="id">页面ID</param>
        /// <returns></returns>
        public bool Delete(string id)
        {
            using (var scope = _dbContextScopeFactory.Create())
            {
                var db = scope.DbContexts.Get<WikeDbContext>();
                
                var count = db.SysPages.Count(c => c.ParentId == id && c.IsDelete==false);
                if (count >0)
                {
                    throw new TipInfoException("请先删除下级数据");
                } 
                var delete = db.SysPages.Include(x => x.SysRoles).FirstOrDefault(c => c.Id == id);
                if (delete != null)
                    delete.IsDelete = true;


                return scope.SaveChanges() > 0;
            }
        }

        /// <summary>
        /// 获取递归后的菜单树
        /// </summary>
        /// <returns></returns>
        public IList<NavTreeModel> GetNavTreeModels()
        {
            using (var scope = _dbContextScopeFactory.CreateReadOnly())
            {
                var db = scope.DbContexts.Get<WikeDbContext>();
                var pages = db.SysPages.OrderBy(x=>x.PageCode).Where(x => x.IsUsed == true && x.IsDelete==false).ToList();
                var trees = new List<NavTreeModel>();
                var resultTrees = new List<NavTreeModel>();
                _mapper.Map(pages, trees);
                BuildTree(trees, string.Empty, null, ref resultTrees);
                return resultTrees;
            }
        }

        /// <summary>
        /// 根据父节点的ID，获取子节点
        /// </summary>
        /// <param name="parentId">父节点ID</param>
        /// <param name="isUsed">默认查询已启用的,如果为null，则表示查询包含启用和未启用的页面</param>
        /// <returns></returns>
        public IList<ZTreeModel> GetByParentId(string parentId, bool? isUsed = true)
        {
            using (var scope = _dbContextScopeFactory.CreateReadOnly())
            {
                var db = scope.DbContexts.Get<WikeDbContext>();
                var query = db.SysPages.Where(x=>x.IsDelete ==false);
                if (isUsed.HasValue)
                {
                    query = query.Where(x => x.IsUsed == isUsed.Value && x.IsDelete ==false);
                }
                query = parentId == string.Empty ? query.Where(x => x.ParentId == null || x.ParentId==string.Empty)
                    : query.Where(x => x.ParentId == parentId);
                return query.OrderBy(x=>x.PageCode).Select(x => new ZTreeModel
                {
                    id = x.Id,
                    name = x.PageName,
                    isParent = db.SysPages.Any(p => p.ParentId == x.Id && p.IsDelete==false)
                }).ToList();
            }
        }

        /// <summary>
        /// 构造递归树
        /// </summary>
        /// <param name="trees">所有的数据源</param>
        /// <param name="parentId">父节点ID</param>
        /// <param name="parentTree">父类别</param>
        /// <param name="resultTrees">结果树</param>
        public void BuildTree(List<NavTreeModel> trees, string parentId, NavTreeModel parentTree, ref List<NavTreeModel> resultTrees)
        {
            var children = trees.Where(x => x.ParentId == parentId).ToList();
            if (parentId.IsBlank())
            {
                resultTrees.AddRange(children);
            }
            foreach (var tree in children)
            {
                BuildTree(trees, tree.Id, tree, ref resultTrees);
                parentTree?.Children.Add(tree);
            }
        }

        /// <summary>
        /// 获取
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        public PageEditModel Find(string id)
        {
            using (var scope = _dbContextScopeFactory.CreateReadOnly())
            {
                var db = scope.DbContexts.Get<WikeDbContext>();
                var entity = db.SysPages.Load(id);
                var page = _mapper.Map<SysPage, PageEditModel>(entity);
                if (entity.ParentId.IsNotBlank())
                {
                    var parent = db.SysPages.Load(entity.ParentId);
                    page.ParentPageName = parent.PageName;
                }
                return page;
            }
        }

        /// <summary>
        /// 获取路径码
        /// </summary>
        /// <param name="db"></param>
        /// <param name="parentPageId"></param>
        /// <returns></returns>
        private string GetPathCode(IWikeDbContext db, string parentPageId)
        {
            //顶级页面
            List<string> existCodes;
            var parentPathCode = string.Empty;
            if (parentPageId.IsBlank())
            {
                existCodes = db.SysPages.Where(x => x.ParentId == null || x.ParentId == string.Empty)
                    .Select(x => x.PathCode).ToList();
            }
            else
            {
                var page = db.SysPages.Load(parentPageId);
                parentPathCode = page.PathCode;

                existCodes = db.SysPages.Where(x => x.ParentId == parentPageId)
                    .Select(x => x.PathCode).ToList()
                    .Select(x => x.Substring(page.PathCode.Length, 2)).ToList();
            }
            var pathCode = CodeTable.SysPathCodes
                    .OrderBy(x => x)
                    .First(x => !existCodes.Contains(x));
            return parentPathCode + pathCode;
        }

        /// <summary>
        /// 获取ztree的树
        /// </summary>
        /// <returns></returns>
        public List<ZTreeModel> GetTrees()
        {
            using (var scope = _dbContextScopeFactory.CreateReadOnly())
            {
                var db = scope.DbContexts.Get<WikeDbContext>();
                var list = db.SysPages.OrderBy(x => x.PageCode).Where(m => m.IsUsed == true && m.IsDelete ==false).ToList();
                
                var result = _mapper.Map<List<SysPage>, List<ZTreeModel>>(list);
                result.ForEach(t => t.open = true);
                return result;
            }
        }

        /// <summary>
        /// 根据用户Id获取用户的页面权限
        /// </summary>
        /// <param name="id">用户Id</param>
        /// <returns></returns>
        public IList<PageModel> GetPagesByUserId(string id)
        {
            using (var scope = _dbContextScopeFactory.CreateReadOnly())
            {
                var db = scope.DbContexts.Get<WikeDbContext>();
                var query = db.SysPages.Where(m => m.IsUsed == true && m.IsDelete ==false);
                //Todo 加入UserId
                query = query.Where(x => x.SysRoles.Any(r => r.SysUsers.Any(u => u.Id == id)));
                return query.OrderBy(x=>x.PageCode).ProjectTo<PageModel>(_configurationProvider).ToList();
            }
        }

        /// <summary>
        /// 检测用户是否有权限
        /// </summary>
        /// <param name="userId">用户Id</param>
        /// <param name="pagePath">页面地址</param>
        /// <returns></returns>
        public bool HasRight(string userId, string pagePath)
        {
            using (var scope = _dbContextScopeFactory.CreateReadOnly())
            {
                var db = scope.DbContexts.Get<WikeDbContext>();
                var query = db.SysPages.Where(m => m.IsUsed == true && pagePath.StartsWith(m.PagePath));
                return query.Any(x => x.SysRoles.Any(r => r.SysUsers.Any(u => u.Id == userId)));
            }
        }

        public PageModel FindByPagePath(string pathcode)
        {
            using (var scope = _dbContextScopeFactory.CreateReadOnly())
            {
                var db = scope.DbContexts.Get<WikeDbContext>();
                var entity = db.SysPages.FirstOrDefault(c => c.PagePath.ToLower() == pathcode.ToLower());
                var page = _mapper.Map<SysPage, PageModel>(entity);
                
                return page;
            }
        }

        public PagedResult<PageModel> Query(PageFilter filters)
        {
            using (var scope = _dbContextScopeFactory.CreateReadOnly())
            {
                var db = scope.DbContexts.Get<WikeDbContext>();
                var query = db.SysPages.Where(x=>x.IsDelete ==false);
                if (filters.keywords.IsNotBlank())
                {
                    query = query.Where(x => x.PageName.Contains(filters.keywords));
                }
                return query.OrderByCustom(filters.sidx, filters.sord)
                    .Select(x => new PageModel
                    {
                        Id = x.Id,
                        ParentId= x.ParentId,
                        PageCode = x.PageCode,
                        PageName = x.PageName,
                        PagePath = x.PagePath,
                        Description = x.Description,
                        IsUsed = x.IsUsed,
                        CssName = x.CssName
                    }).Paging(filters.page, filters.rows);
            }
        }
    }
}
